#!/usr/bin/python3
# -*- coding:utf-8 -*-
# @Author  : 李吉凯
# @Email   : lijk34925@hundsum.com
# @Time    : 2022/5/10 9:42
# @File    : Common.py
import importlib
import json
import re
import socket
import sys
import os
import configparser
import collections
import xlrd
import datetime
from collections import OrderedDict

from BladeFerm.Lib.Log import log_init


global MenuName
global MethodName
global InputData
global UIExpect
global InputElement
global config
global test_module
global logFile


def is_port_open(ip, port, timeout=1):
    """
    测试指定IP和端口的可访问性。

    参数:
    ip (str): 要测试的IP地址。
    port (int): 要测试的端口号。
    timeout (int): 尝试连接的超时时间，默认为1秒。

    返回:
    bool: 如果端口开放且可访问，则返回True；否则返回False。
    """
    try:
        # 创建一个socket对象
        with socket.create_connection((ip, port), timeout):
            return True
    except (socket.error, ConnectionRefusedError, ConnectionResetError, ConnectionAbortedError, TimeoutError):
        # 如果连接失败，则认为端口不可访问
        return False


# 改动：从环境变量获取自动化脚本的工作目录，方便脚本查找和drive查找      --- 20210507 李吉凯
# basePath = 'E:\Web_AutoTest\FERM_FSK\全面风险管理\web应用'
ROOT_PATH = os.environ.get('HSPYTHONFRAME_WORKSPACE')

if ROOT_PATH is None:
    ROOT_PATH = sys.path[-1]
iniPath = os.path.join(ROOT_PATH, 'qturbo.ini')

config = configparser.ConfigParser()
if not os.path.exists(iniPath):
    iniPath = "../qturbo.ini"

config.read(iniPath, encoding='utf-8')
basePath = config.get('ScriptsDir', 'scripts_dir')
log_level = config.get('ReportLevel', 'reportlevel')

# 路径拼接符号，windows是 \\ , linux是 / ；
pathFlag = os.sep

# 定义一个文件下载的路径
download_dir = config.get('ScriptsDir', 'download_dir')
if download_dir == "" or download_dir == " ":
    DownPath = os.path.join(ROOT_PATH, 'DownFiles')
else:
    DownPath = download_dir
UploadPath = os.path.join(ROOT_PATH, 'UploadFiles')

# 定义驱动存放路径，在PythonFrame路径下的Tools文件夹下
toolFolderPath = ROOT_PATH + pathFlag + 'Tools' + pathFlag

currentTime = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
currentDate = datetime.datetime.now().strftime('%Y%m%d')
# 定义日志和失败截图保存的路径，在PythonFrame路径下的logs文件夹下  20211014
logFilePath = ROOT_PATH + pathFlag + 'Logs' + pathFlag + currentDate
isExist = os.path.exists(logFilePath)
if not isExist:
    os.makedirs(logFilePath)
logFile = logFilePath + pathFlag + currentDate + '.log'

# 用于区分本地调试还是blade平台测试，加载不同的日志模块
test_module = True if config.get('TestFlow', 'PythonUnitFilter') == '1' else False
if test_module:
    from qturboframe.lib.report.log import logger
else:
    logger = log_init(logFile, log_level)


# 运行脚本
def run_script(script_path, function_name, *args):
    pattern = re.compile(r'[\\]+')
    script_path = pattern.sub('/', script_path)
    script_path = script_path.replace('.py', '').replace('/', '.')
    logger.debug(f'导入的模块：{script_path},方法：{function_name}, 参数是：{args}')
    # 动态导入脚本
    module = importlib.import_module(script_path.lstrip('.'))
    # 调用脚本中的函数
    return getattr(module, function_name)(*args)


# 转化成有序字典
def toOrderedDict(data: dict):
    if data:
        OrderedDict(data)
    else:
        data = OrderedDict()
    return data


# 读取excel内容
def dealXlsElement(elementPath, value_id=1, sheet_index=0):
    InputElement = collections.OrderedDict()
    with xlrd.open_workbook(elementPath) as data:
       table = data.sheet_by_index(sheet_index)  # 通过索引顺序获取工作表
       for i in range(table.nrows):
           InputElement[table.cell(i, 0).value] = table.cell(i, value_id).value
    return InputElement


# 读取配置文件
def readConfigFile(section, option):
    """
    sections:配置文件中[]中的值
    options:每组中的键
    """
    config = configparser.RawConfigParser()
    try:
        config.readfp(open(iniPath))
        value = config.get(section, option)
    except configparser.NoSectionError:
        value = None
    return value


# 配置文件写入
def writeConfigFile(section, option, value):
    config = configparser.ConfigParser()
    try:
        config.readfp(open(iniPath, encoding='utf-8'))
        config.set(section, option, value)
        config.write(open(iniPath, "w", encoding='utf-8'))
    except Exception as e:
        raise e


# 装饰器，传参
def skip_Step(flag=None):
    def decorate(func):
        def wrapper(*args, **kwargs):
            if flag:
                logger.info(f'Flag is {flag}, Run function {func}')
                return func(*args, **kwargs)  ##调用函数
            else:
                logger.warn(f'Flag is {flag}, Skip function {func}')
                return None
        return wrapper
    return decorate


# 装饰器，不传参
def judge_Run_Step(func):
    def wrapper(*args, **kwargs):
        if args[0] == '' or args[0] == ' ' or args[0] is None:
            logger.warn(f'Flag is {args[0]}, Skip function {func}')
            return None
        else:
            return func(*args, **kwargs)  ##调用函数
    return wrapper


# 装饰器，处理入参
def data_processing(func):
    def deal_dict(input_data):
        new_input_data = dict()
        for k, v in input_data.items():
            if v and isinstance(v, str):
                v = v.replace('(Object)', "")
                v = v.replace('(Number)', "")
                v = v.replace('(ArrayNoKey)', "")
                if re.search(r'Object', k):
                    k = k.split('(Object')[0]
                    v2 = json.loads(v)
                    v2.pop('GroupID', None)
                    new_input_data[k] = deal_dict(v2)
                elif re.search(r'Number', k):
                    k = k.split('(Number')[0]
                    v2 = eval(v)
                    # v2.pop('GroupID')
                    new_input_data[k] = v2
                elif re.search(r'ArrayNoKey', k):
                    k = k.split('(ArrayNoKey')[0]
                    v2 = json.loads(v.replace("'", "\""))
                    # v2.pop('GroupID')
                    new_input_data[k] = v2
                elif re.search(r'Array', k):
                    k = k.split('(Array')[0]
                    v2 = json.loads(v.replace("'", "\""))
                    sec_list = list()
                    for unit in v2:
                        sec_unit_dict = deal_dict(unit)
                        sec_list.append(sec_unit_dict)
                    new_input_data[k] = sec_list
                # elif (not v.startswith('{{') and v.startswith('{') and v.endswith('}')) \
                #         or (v.startswith('[') and v.endswith(']')):
                #     new_input_data[k] = eval(v)
                else:
                    new_input_data[k] = v
            elif v == '' and isinstance(v, str):
                continue
            else:
                new_input_data[k] = v
        return new_input_data

    def deal_input(input_data):
        if isinstance(input_data, dict):
            return deal_dict(input_data)
        elif isinstance(input_data, list):
            result = []
            for unit in input_data:
                result.append(deal_dict(unit))
            return result
        else:
            return input_data

    def deal_except(except_data):
        '''
        处理期望数据，可能的数据类型有：
            {
             '期望': "[1, 3, '4']",
             '期望文本': '系统管理员',
             '期望数据': "{'姓名': 'lijk', '性别': '男'}"
             }
        Args:
            except_data:

        Returns:

        '''
        new_input_data = dict()
        for k, v in except_data.items():
            if isinstance(v, str):
                if v.startswith('[') and v.endswith(']') and is_str(v) is False:
                    new_input_data[k] = eval(v)
                elif v.startswith('{') and v.endswith('}'):
                    new_input_data[k] = eval(v)
                else:
                    new_input_data[k] = v
            else:
                new_input_data[k] = v
        return new_input_data


    def is_str(v):
        if v.startswith('[') and v.endswith(']'):
            if v.count('[') != 1 or v.count(']') != 1:
                return True
            else:
                return False
        return True

    def wrapper(*args, **kwargs):
        raw_input_data = input_data = raw_ui_expect = except_data = {}
        if args:
            raw_input_data = args[0]
            input_data = deal_input(raw_input_data)
            res_list = [input_data]
            if len(args) > 1:
                raw_ui_expect = args[1]
                except_data = deal_except(raw_ui_expect)
                res_list.append(except_data)
            args = res_list
        if kwargs:
            raw_input_data = kwargs.get('input_data', None)
            raw_ui_expect = kwargs.get('ui_expect', None)
            if raw_input_data:
                input_data = deal_input(raw_input_data)
                kwargs.update({'input_data': input_data})
            if raw_ui_expect:
                except_data = deal_except(raw_ui_expect)
                kwargs.update({'ui_expect': except_data})
        logger.info(f"blade's origin data, input_data : {raw_input_data}")
        logger.info(f"frame processed data, input_data : {input_data}")
        logger.info(f"blade's origin data, ui_except : {raw_ui_expect}")
        logger.info(f"frame processed data, ui_except : {except_data}")
        return func(*args, **kwargs)  ##调用函数
    return wrapper


@data_processing
def demo_data(input_data=None, ui_expect=None):
    print(input_data)
    print(ui_expect)


if __name__ == '__main__':
    input_data = {'列表表格操作（选择操作行数据）(Object)': '{"GroupID":"1","业务类型":"股票","任务名称":"全表全量-1"}', '查询内容(Object)': '{"GroupID":"1","业务类型":"股票","任务名称":"全表全量-1"}', '基础信息(Object)': '{"GroupID":"1","业务类型":"股票","业务部门":"O32","任务优先级":"8","任务描述":"uitest copy","开始日期":"2022/06/13","文件编码":"GBK","比对模式":"全表全量比对","自动上传云服务":"自动上传"}', '选择比对表(Object)': '{"GroupID":"1","比对表单(ArrayNoKey)":[{"合成基准表数据源":"oracle_30_34_TEST1","比对资讯源类型":"oracle"}],"选择内容(ArrayNoKey)":[{"比对数据表":"A_WANGTEST1","比对资讯源":"oracle_30_34_UIS"},{"是否基准基准表":true,"比对数据表":"A_WANGTEST3","比对资讯源":"oracle_30_34_UIS"}]}', '主键及比对字段选择(Object)': '{"GroupID":"1","是否主键(ArrayNoKey)":["TECH_UPDT_TIME"],"是否比对(ArrayNoKey)":["ID1","ID2"],"显示且不比对(ArrayNoKey)":["TECH_UPDT_TIME","D_YWRQ"],"重判定参考(ArrayNoKey)":["TECH_UPDT_TIME","D_YWRQ"]}', '过滤规则(Object)': '{"GroupID":"1","oracle_30_34_UIS.A_WANGTEST1 过滤规则":"where 1\\u003e2","oracle_30_34_UIS.A_WANGTEST3 过滤规则":"where 2\\u003e3"}', '触发器名称': 'zhhtestcron'}
    # demo_data(input_data)

    d = {'查询筛选(Object)': '{"GroupID":"1","接口标准":"O32"}', '定位修改记录(Object)': '{"GroupID":"1","ID":"37"}', '修改内容(Object)': '{"GroupID":"1","接口字段(Array)":"[{\'* 字段英文名\': \'id\', \'字段中文名\': \'编码\', \'* 字段类型\': \'\', \'字段口径\': \'\'}, {\'* 字段英文名\': \'name\', \'字段中文名\': \'姓名\', \'* 字段类型\': \'varchar(20)\', \'字段口径\': \'8\'}]","接口详情(Object)":{"备注":"自动化测试-修改后的接口","接口名称":"dyt_test","接口标准":"O32"}}'}
    demo_data(d)